#ifndef INCLUDE_MY_STRING_H_
#define INCLUDE_MY_STRING_H_

#include <iostream>


class MyString {
public:
    /**
     * 构造函数和析构函数
     *
     * 知识点: 构造函数和析构函数，拷贝构造
     */
    MyString();                     // 默认构造函数，初始化一个空串
    MyString(const char* str);      // 用一个C风格字符串初始化
    MyString(const MyString& str);  // 拷贝构造函数
    ~MyString();                    // 析构函数

    /**
     * 一般函数
     *
     * 知识点: 类的常量成员函数
     *      写法: 在函数声明后面加 const，就像下面两个函数
     *      作用: 告诉编译器，这个函数不会修改类的成员变量（在MyString中，即不会修改 data_ 和 size_）
     */
    int size() const;           // 返回字符串长度
    int max_size() const;       // 返回字符串最大长度，即分配的内存大小 - 1

    /**
     * 重载运算符
     *
     * 知识点:
     *      重载运算符
     *      友元函数
     *      返回值是引用的函数（这样的函数返回效率高）
     */
    MyString& operator=(const MyString& str);                               // 重载赋值运算符
    friend MyString operator+(const MyString& lhs, const MyString& rhs);    // 重载加法运算符：用于连接两个字符串
    // MyString operator+(const MyString& str) const;                          // 思考：如果 + 携程成员函数，会有什么问题？
    MyString& operator+=(const MyString& str);                              // 重载加等于运算符：用于连接两个字符串
    bool operator==(const MyString& str) const;                             // 重载等于运算符：用于判断两个字符串是否相等

    /**
     * 重载输入输出运算符
     *      重载 operator<< 可用于 cout
     *      重载 operator>> 用于 cin（一般不需要）
     */
    friend std::ostream& operator<<(std::ostream& os, const MyString& str); // 重载输出运算符

    /**
     * 重载下标运算符
     */
    char& operator[](int index);                // 用于修改字符串中的字符
    const char& operator[](int index) const;    // 用于读取字符串中的字符

private:
    /**
     * 私有方法：该类外面不能调用，只能被类的成员函数调用
     */
    void expand(int need_size);                 // 扩展字符串的 max_size

private:
    /**
     * 成员变量：
     * char *data_：用于存储字符串的数组
     *      注意，这里的 data_ 是一个指针，指向一个 char 类型的数组
     *      因此，data_本身需要用new动态分配内存
     *      所以：
     *          1. 构造函数中需要用 delete 释放内存
     *          2. MyString 中字符串其实存储在堆中
     *      思考：
     *          1. 如果 MyString 作为函数参数传递，那么需要传递多大的内存？
     *          答案：指针8字节+size_4字节 = 12字节，只有栈上的数据传参时才会复制用来传递
     *          2. 基于上一个问题，那么对于c++中的string，直接传参string时需要复制很多内存吗？
     *          答案：不需要，string的字符串同样也是在堆上的，传递参数只需要传递指向堆上字符串的指针
     * int size_：当前 data_ 的最大容量（不是字符串的大小）
     */
    char* data_;
    int size_;
};

#endif  // INCLUDE_MY_STRING_H_
